package elicecn.util;

import java.util.Random;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * 数字转换工具
 * 
 * @author 屹砾
 * @email eli.wuhan@gmail.com
 * @time 2009-1-20
 */
public class DigitalUtils {
	protected static final Log log = LogFactory.getLog(DigitalUtils.class);
	private static final String DIGITAL_STRING = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/";
	private static final char[] DIGITAL = DIGITAL_STRING.toCharArray();
	private static final Random RND = new Random();

	/**
	 * 将字节数组转换成16进制数字
	 * 
	 * @param bytes
	 *            字节数组
	 * @return 16进制数字
	 */
	public static char[] toHex(byte[] bytes) {
		return toHex(bytes, DIGITAL);
	}

	/**
	 * 将长整型数字转换成16进制数字
	 * 
	 * @param longValue
	 *            长整型数字
	 * @return 16进制数字
	 */
	public static char[] toHex(long longValue) {
		return toHex(longValue, DIGITAL);
	}

	/**
	 * 将整型数字转换成16进制数字
	 * 
	 * @param intValue
	 *            整型数字
	 * @return 16进制数字
	 */
	public static char[] toHex(int intValue) {
		return toHex(intValue, DIGITAL);
	}

	/**
	 * 
	 * @param bytes
	 *            字节数组
	 * @return 16进制数字
	 */
	public static char[] toHex64(byte[] bytes) {
		return toHex64(bytes, DIGITAL);
	}

	/**
	 * 将字节数组转换成16进制数字
	 * 
	 * @param bytes
	 * 
	 * @param digitals
	 *            16进制数字字符数组
	 * @return 16进制数字
	 */
	public static char[] toHex(byte[] bytes, char[] digitals) {
		char[] ch = new char[bytes.length * 2];
		for (int i = 0, j = 0; i < bytes.length; i++) {
			ch[j++] = digitals[(bytes[i] >> 4) & 0xF];
			ch[j++] = digitals[bytes[i] & 0xF];
		}
		return ch;
	}

	/**
	 * 将长整型数字转换成16进制数字
	 * 
	 * @param longValue
	 *            长整型数字
	 * @param digitals
	 *            16进制数字字符数组
	 * @return 16进制数字
	 */
	public static char[] toHex(long longValue, char[] digitals) {
		char[] ch = new char[16];
		for (int i = 0; i < 16; i++) {
			ch[i] = digitals[(int) (longValue >> (15 - i) * 4) & 0xF];
		}
		return ch;
	}

	/**
	 * 将整型数字转换成16进制数字
	 * 
	 * @param intValue
	 *            整型数字
	 * @param digitals
	 *            16进制数字字符数组
	 * @return 16进制数字
	 */
	public static char[] toHex(int intValue, char[] digitals) {
		char[] ch = new char[8];
		for (int i = 0; i < 8; i++) {
			ch[i] = digitals[(int) (intValue >> (7 - i) * 4) & 0xF];
		}
		return ch;
	}

	/**
	 * 将字节数组转换成64进制数字
	 * 
	 * @param bytes
	 *            字节数组
	 * @param digitals
	 *            64进制数字字符数组
	 * @return 64进制数字
	 */
	public static char[] toHex64(byte[] bytes, char[] digitals) {
		int length = bytes.length % 3 == 0 ? bytes.length * 4 / 3
				: bytes.length * 4 / 3 + 1;
		char[] ch = new char[length];
		for (int i = length - 1, j = i * 3 / 4, k = length - 1; i >= 0; i--, j = i * 3 / 4) {
			switch ((k - i) % 4) {
			case 0:
				ch[i] = DIGITAL[bytes[j] & 0x3F];
				break;
			case 1:
				if (i == 1 && j == 0) {
					ch[i] = DIGITAL[((bytes[j + 1] >>> 6) & 0x3)
							+ ((bytes[j] & 0xF) << 2)];
				} else if (i == 0 && j == 0) {
					ch[i] = DIGITAL[(bytes[j] >>> 6) & 0x3];
				} else {
					ch[i] = DIGITAL[((bytes[j] >>> 6) & 0x3)
							+ ((bytes[j - 1] & 0xF) << 2)];
				}
				break;
			case 2:
				if (i == 0 && j == 0) {
					ch[i] = DIGITAL[bytes[j] >>> 4 & 0xF];
				} else {
					ch[i] = DIGITAL[(bytes[j + 1] >>> 4 & 0xF)
							+ ((bytes[j] & 0x3) << 4)];
				}
				break;
			case 3:
				ch[i] = DIGITAL[(bytes[j] >>> 2) & 0x3F];
				break;
			}
		}
		return ch;
	}

	/**
	 * 将长整型数字转换成64进制数字
	 * 
	 * @param num
	 *            长整型数字
	 * @return 64进制数字
	 */
	public static String toHex64(long num) {
		StringBuffer buf = new StringBuffer();
		while (num != 0) {
			buf.append(DIGITAL[(int) (num & 0x3f)]);
			num = num >>> 6;
		}
		return buf.reverse().toString();
	}

	/**
	 * 将64进制数字转换成长整型数字
	 * 
	 * @param hex64
	 *            64进制数字
	 * @return 长整型数字
	 */
	public static long hex64ToLong(String hex64) {
		return hex64ToLong(hex64, DIGITAL_STRING);
	}

	/**
	 * 将64进制数字转换成长整型数字
	 * 
	 * @param hex64
	 *            64进制数字
	 * @param charArray
	 *            64进制数字字典
	 * @return 长整型数字
	 */
	public static long hex64ToLong(String hex64, String charArray) {
		long num = 0L;
		int length = hex64.length();
		for (int i = 0; i < length; i++) {
			num = (num << 6) + charArray.indexOf(hex64.charAt(i));
		}
		return num;
	}

	/**
	 * 生成随机10进制字符串。
	 * 
	 * @param length
	 *            字符串长度
	 * @return 随机字符串
	 */
	public static String generatingRandomDecimal(int length) {
		return generatingRandom(length, 10, 0);
	}

	/**
	 * 生成随机16进制字符串。
	 * 
	 * @param length
	 *            字符串长度
	 * @return 随机字符串
	 */
	public static String generatingRandomHex(int length) {
		return generatingRandom(length, 16, 0);
	}

	/**
	 * 生成随机64进制字符串，包含大小写字母、数字、西文加号和反斜杠。
	 * 
	 * @param length
	 *            字符串长度
	 * @return 随机字符串
	 */
	public static String generatingRandomHex64(int length) {
		return generatingRandom(length, 64, 0);
	}

	/**
	 * 生成随机字符串，包含大小写字母和数字。
	 * 
	 * @param length
	 *            字符串长度
	 * @return 随机字符串
	 */
	public static String generatingRandomHex62(int length) {
		return generatingRandom(length, 62, 0);
	}

	/**
	 * 生成随机字符串，包含小写字母。
	 * 
	 * @param length
	 *            字符串长度
	 * @return 随机字符串
	 */
	public static String generatingRandomLowerCaseCharacter(int length) {
		return generatingRandom(length, 26, 10);
	}

	/**
	 * 生成随机字符串，包含大写字母。
	 * 
	 * @param length
	 *            字符串长度
	 * @return 随机字符串
	 */
	public static String generatingRandomUpperCaseCharacter(int length) {
		return generatingRandom(length, 26, 36);
	}

	/**
	 * 生成随机字符串，包含大小写字母。
	 * 
	 * @param length
	 *            字符串长度
	 * @return 随机字符串
	 */
	public static String generatingRandomCharacter(int length) {
		return generatingRandom(length, 52, 10);
	}

	/**
	 * 生成随机字符串
	 * 
	 * @param length
	 *            字符串长度
	 * @param size
	 *            数组最大范围
	 * @param offset
	 *            数组偏移
	 * @return 随机字符串
	 */
	protected static String generatingRandom(int length, int size, int offset) {
		byte[] bytes = new byte[length];
		RND.nextBytes(bytes);
		StringBuffer buf = new StringBuffer();
		for (int i = 0; i < length; i++) {
			int idx = Math.abs(bytes[i]) % size + offset;
			buf.append(DIGITAL[idx]);
		}
		return buf.toString();
	}
}
